package servlet;

import config.Action;
import config.ActionMapping;
import config.Forward;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.xml.sax.SAXException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 石小俊
 * @date 2023年11月01日 16:54
 */
@WebServlet(urlPatterns = "*.do",loadOnStartup = 1,initParams = {
        @WebInitParam(name = "configLocation",value = "actions.xml")
})
public class ActionServlet extends HttpServlet {

    private ActionMapping actionMapping;
    private Map<String,Object> actions;

    @Override
    public void init() throws ServletException {
        actions = new HashMap<>();
        // 解析XML
        Digester digester = DigesterLoader.createDigester(ActionServlet.class.getClassLoader().getResource("config/rule.xml"));
        actionMapping = new ActionMapping();
        digester.push(actionMapping);
        String configLocation = getInitParameter("configLocation");
        if(configLocation == null){
            throw new ServletException("未找到配置文件");
        }
        try {
            digester.parse(ActionServlet.class.getClassLoader().getResourceAsStream(configLocation));
        } catch (IOException e) {
            throw new ServletException(e.getMessage());
        } catch (SAXException e) {
            throw new ServletException(e.getMessage());
        }
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 实现XML所需要的功能
        System.out.println(actionMapping);
        // 获取浏览器发送的请求
        String path = request.getServletPath();
        // 此时发送的请求格式为:*.do
        // 但是在配置文件中是没有后缀的
        // 如果想要在配置文件中找到对应的请求,必须去除后缀后进行查找
        path = path.substring(0,path.lastIndexOf("."));
        System.out.println("path:"+path);

        // 根据当前请求在配置文件中找到对应的Action配置
        Action action = actionMapping.findAction(path);
        System.out.println(action);
        // 如果当前配置不存在,抛出异常
        if(action == null){
            throw new ServletException(path+".do在配置文件中没有与之对应的请求");
        }

        try {
            // 找到配置之后,找到与之对应的类与方法,并执行对应方法
            // 此时通过反射来实现
            Class actionClass = Class.forName(action.getType());
            // 从Map集合中取出对应的对象
            Object obj = actions.get(action.getType());
            if(obj == null){
                // 如果没有取到对象,说明尚未创建过对应的对象
                // 因此,当前集合中不存在该对象
                // 此时,创建该对象
                obj = actionClass.newInstance();
                // 并将创建好的对象存放到Map集合中
                actions.put(action.getType(),obj);
            }

            // 获取目标方法
            Method method = actionClass.getMethod(action.getParameter(),HttpServletRequest.class,HttpServletResponse.class);
            // 执行目标方法,并获取方法的返回值
            String result = (String) method.invoke(obj,request,response);
            if(request == null){
                throw new ServletException("当前方法没有返回值,请通过Ajax实现");
            }

            // 根据方法返回值找到对应的Forward配置
            Forward forward = action.findForward(result);
            System.out.println(forward);
            if(forward == null){
                throw new ServletException("根据方法返回值"+result+"在配置文件中没有找到对应的配置");
            }

            // 进行页面的跳转
            // 根据Forward中redirect属性选择转发或者重定向
            // 如果redirect值为true
            if(forward.isRedirect()){
                // 则选择重定向,重定向的地址为path
                response.sendRedirect(request.getContextPath()+forward.getPath());
            } else {
                // 否则选择转发,转发地址为path
                request.getRequestDispatcher(forward.getPath()).forward(request,response);
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new ServletException(e.getMessage());
        }

    }
}
